#include "ServerBootstrap.h"
#include "ReactorThreadPool.h"
#include "Acceptor.h"
#include "Log.h"

namespace dsth {

ServerBootstrap::ServerBootstrap(EventLoop* loop, const InetSocketAddress& addr)
    : loop_(loop),
    acceptor_(new Acceptor(loop, addr)),
    conn_id_(1),
    pool_(NULL) {
    acceptor_->SetAcceptHandler(std::make_pair(this, &ServerBootstrap::OnNewConnection));
}

ServerBootstrap::ServerBootstrap(ReactorThreadPool *pool, const InetSocketAddress& addr) 
    : loop_(pool->GetNextEventLoop()),
    acceptor_(new Acceptor(loop_, addr)),
    conn_id_(1),
    pool_(pool) {
    acceptor_->SetAcceptHandler(std::make_pair(this, &ServerBootstrap::OnNewConnection));
}

ServerBootstrap::~ServerBootstrap() {
    for (ConnectionMap::iterator it = conn_map_.begin();
        it != conn_map_.end(); ++it) {
        assert(it->second);
        delete it->second;
    }
}

void ServerBootstrap::Run() {
    // call acceptor_.Listen(), but run it in loop
    loop_->RunInLoop(std::make_pair(acceptor_.get(), &Acceptor::Listen));
    if (pool_) {
        pool_->Run();
    }
}

void ServerBootstrap::OnNewConnection(int sockfd, const InetSocketAddress& peer_addr) {
    EventLoop* loop = GetNextEventLoop();
    assert(loop);
    InetSocketAddress host_addr(net::GetHostAddr(sockfd));
    LOG_DEBUG("[ServerBootstrap::OnNewConnection] host addr=%s, peer addr=%s", 
        host_addr.ToHostPortFormat().c_str(), peer_addr.ToHostPortFormat().c_str());
    Connection* conn = new Connection(loop,
        conn_id_, sockfd, host_addr, peer_addr);
    conn_map_[conn_id_++] = conn;
    conn->SetConnectionHandler(conn_handler_);
    conn->SetMessageHandler(msg_handler_);
    conn->SetWriteCompletedHandler(write_completed_handler_);
    conn->SetDisConnectionHandler(std::make_pair(this, &ServerBootstrap::OnCloseConnection));
    loop->RunInLoop(std::make_pair(conn, &Connection::ConnectEstablished));
}

void ServerBootstrap::OnCloseConnection(Connection* conn) {
    LOG_INFO("[ServerBootstrap::OnCloseConnection] connection count:%d, killing id:%d.",
        conn_map_.size(), conn->GetId());
    //TODO: If it's half close, chose to close sock by return value and may need a default handler.
    dis_conn_handler_(conn);
    ConnectionMap::iterator it = conn_map_.find(conn->GetId());
    //TODO:FIXME
    if (it == conn_map_.end()) {
        LOG_ERROR("####### map find id:%d",conn->GetId());
        return;
    }
    size_t n = conn_map_.erase(conn->GetId());
    assert(n == 1);
    conn->ConnectDestroy();
}

EventLoop* ServerBootstrap::GetNextEventLoop() {
    EventLoop* loop = NULL;
    if (pool_) {
        loop =  pool_->GetNextEventLoop();
    }
    return loop ? loop : loop_;
}

} // namespace
